array_unshift( $ipchain, $ip );
}
- # Step through XFF list and find the last address in the list which is a trusted server
- # Set $ip to the IP address given by that trusted server, unless the address is not sensible (e.g. private)
+ # Step through XFF list and find the last address in the list which is a
+ # trusted server. Set $ip to the IP address given by that trusted server,
+ # unless the address is not sensible (e.g. private). However, prefer private
+ # IP addresses over proxy servers controlled by this site (more sensible).
foreach ( $ipchain as $i => $curIP ) {
$curIP = IP::canonicalize( $curIP );
- if ( wfIsTrustedProxy( $curIP ) ) {
- if ( isset( $ipchain[$i + 1] ) ) {
- if ( $wgUsePrivateIPs || IP::isPublic( $ipchain[$i + 1] ) ) {
- $ip = $ipchain[$i + 1];
- }
+ if ( wfIsTrustedProxy( $curIP ) && isset( $ipchain[$i + 1] ) ) {
+ if ( wfIsConfiguredProxy( $curIP ) || // bug 48919
+ ( IP::isPublic( $ipchain[$i + 1] ) || $wgUsePrivateIPs )
+ ) {
+ $ip = IP::canonicalize( $ipchain[$i + 1] );
+ continue;
}
- } else {
- break;
}
+ break;
}
}
/**
* @dataProvider provideGetIP
*/
- function testGetIP( $expected, $input, $squid, $private, $description ) {
+ function testGetIP( $expected, $input, $squid, $xffList, $private, $description ) {
$_SERVER = $input;
$this->setMwGlobals( array(
'wgSquidServersNoPurge' => $squid,
'wgUsePrivateIPs' => $private,
+ 'wgHooks' => array(
+ 'IsTrustedProxy' => array(
+ function( &$ip, &$trusted ) use ( $xffList ) {
+ $trusted = $trusted || in_array( $ip, $xffList );
+ return true;
+ }
+ )
+ )
) );
$request = new WebRequest();
'REMOTE_ADDR' => '127.0.0.1'
),
array(),
+ array(),
false,
'Simple IPv4'
),
'REMOTE_ADDR' => '::1'
),
array(),
+ array(),
false,
'Simple IPv6'
),
'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
),
array( '12.0.0.1', '12.0.0.2' ),
+ array(),
false,
'With X-Forwaded-For'
),
'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
),
array(),
+ array(),
false,
'With X-Forwaded-For and disallowed server'
),
'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
),
array( '12.0.0.1' ),
+ array(),
false,
'With multiple X-Forwaded-For and only one allowed server'
),
array(
- '12.0.0.2',
+ '10.0.0.3',
array(
'REMOTE_ADDR' => '12.0.0.2',
- 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2'
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
),
array( '12.0.0.1', '12.0.0.2' ),
+ array(),
false,
- 'With X-Forwaded-For and private IP'
+ 'With X-Forwaded-For and private IP (from cache proxy)'
),
array(
- '10.0.0.3',
+ '10.0.0.4',
array(
'REMOTE_ADDR' => '12.0.0.2',
- 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2'
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
+ ),
+ array( '12.0.0.1', '12.0.0.2', '10.0.0.3' ),
+ array(),
+ true,
+ 'With X-Forwaded-For and private IP (allowed)'
+ ),
+ array(
+ '10.0.0.4',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.2',
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
),
array( '12.0.0.1', '12.0.0.2' ),
+ array( '10.0.0.3' ),
true,
'With X-Forwaded-For and private IP (allowed)'
),
+ array(
+ '10.0.0.3',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.2',
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.4, 10.0.0.3, 12.0.0.2'
+ ),
+ array( '12.0.0.1', '12.0.0.2' ),
+ array( '10.0.0.3' ),
+ false,
+ 'With X-Forwaded-For and private IP (disallowed)'
+ ),
+ array(
+ '12.0.0.3',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.1',
+ 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
+ ),
+ array(),
+ array( '12.0.0.1', '12.0.0.2' ),
+ false,
+ 'With X-Forwaded-For'
+ ),
+ array(
+ '12.0.0.2',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.1',
+ 'HTTP_X_FORWARDED_FOR' => '12.0.0.3, 12.0.0.2'
+ ),
+ array(),
+ array( '12.0.0.1' ),
+ false,
+ 'With multiple X-Forwaded-For and only one allowed server'
+ ),
+ array(
+ '12.0.0.2',
+ array(
+ 'REMOTE_ADDR' => '12.0.0.2',
+ 'HTTP_X_FORWARDED_FOR' => '10.0.0.3, 12.0.0.2'
+ ),
+ array(),
+ array( '12.0.0.2' ),
+ false,
+ 'With X-Forwaded-For and private IP and hook (disallowed)'
+ ),
);
}